package com.dongrj.framework.core.exception;

import com.dongrj.framework.core.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * @author dongrongjun
 * @date 2020/08/04
 */
@Slf4j
public final class Assert {


    /**
     * 抛出异常
     *
     * @param error 异常信息
     */
    public static <T> T throwsBiz(String error) {
        throw new BusinessException(error);
    }


    /**
     * 抛出异常
     */
    public static <T> T throwsBiz(String messageTemplate, Object... params) {
        String format = String.format(messageTemplate, params);
        log.error(format);
        throw new BusinessException(format);
    }


    /**
     * 抛出异常
     */
    public static <T> T throwsBiz(T t, String messageTemplate, Object... params) {
        String format = String.format(messageTemplate, params);
        log.error(format, t);
        throw new BusinessException(format);
    }


    /**
     * 抛出系统异常
     *
     * @param error 异常信息
     */
    public static <T> T throwsSys(String error) {
        throw new SystemException(error);
    }


    /**
     * 抛出系统异常
     */
    public static <T> T throwsSys(String messageTemplate, Object... params) {
        throw new SystemException(messageTemplate, params);
    }


    /**
     * 非空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T isNull(T t, String error) {
        if (t != null) {
            throw new BusinessException(error);
        }
        return t;
    }


    /**
     * 非空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T nonNull(T t, String error) {
        if (t == null) {
            throw new BusinessException(error);
        }
        return t;
    }


    /**
     * 非空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T notEmpty(T t, String error) {
        return notEmpty(t, error, null);
    }


    /**
     * 非空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T notEmpty(T t, String error, Object logObj) {
        if (ObjectUtils.isEmpty(t)) {
            if (Objects.nonNull(logObj)) {
                log.error("{}-{}", error, logObj);
            }
            throw new BusinessException(error);
        }
        return t;
    }


    /**
     * 空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T isEmpty(T t, String error) {
        return isEmpty(t, error, null);
    }


    /**
     * 空异常检查
     *
     * @param t     参数
     * @param error 异常信息
     */
    public static <T> T isEmpty(T t, String error, Object logObj) {
        if (ObjectUtils.isNotEmpty(t)) {
            if (Objects.nonNull(logObj)) {
                log.error("{}-{}", error, logObj);
            }
            throw new BusinessException(error);
        }
        return t;
    }


    /**
     * 判断
     *
     * @param flag  条件
     * @param error 异常信息
     */
    public static void isTrue(boolean flag, String error) {
        if (!flag) {
            throw new BusinessException(error);
        }
    }

    /**
     * 判断
     *
     * @param flag  条件
     * @param error 异常信息
     */
    public static void isFalse(boolean flag, String error) {
        if (flag) {
            throw new BusinessException(error);
        }
    }

    /**
     * 判断
     *
     * @param flag  条件(为false是抛出异常)
     * @param error 异常信息
     */
    public static void check(boolean flag, String error) {
        if (!flag) {
            throw new BusinessException(error);
        }
    }


    /**
     * 检查值是否在指定范围内
     *
     * @param value 值
     * @param min   最小值（包含）
     * @param max   最大值（包含）
     * @return 检查后的长度值
     * @since 4.1.10
     */
    public static long checkBetween(long value, long min, long max) {
        return checkBetween(value, min, max, "The value must be between %s and %s.", min, max);
    }

    /**
     * 检查值是否在指定范围内
     *
     * @param value            值
     * @param min              最小值（包含）
     * @param max              最大值（包含）
     * @param errorMsgTemplate 异常信息模板，类似于"aa{}bb{}cc"
     * @param params           异常信息参数，用于替换"{}"占位符
     * @return 经过检查后的值
     * @since 5.7.15
     */
    public static long checkBetween(long value, long min, long max, String errorMsgTemplate, Object... params) {
        return checkBetween(value, min, max, () -> new IllegalArgumentException(String.format(errorMsgTemplate, params)));
    }


    /**
     * 检查值是否在指定范围内
     *
     * @param <X>           异常类型
     * @param value         值
     * @param min           最小值（包含）
     * @param max           最大值（包含）
     * @param errorSupplier 错误抛出异常附带的消息生产接口
     * @return 经过检查后的值
     * @throws X if value is out of bound
     * @since 5.7.15
     */
    public static <X extends Throwable> long checkBetween(long value, long min, long max, Supplier<? extends X> errorSupplier) throws X {
        if (value < min || value > max) {
            throw errorSupplier.get();
        }

        return value;
    }


    /**
     * 检查值是否在指定范围内
     *
     * @param value 值
     * @param min   最小值（包含）
     * @param max   最大值（包含）
     * @return 检查后的长度值
     * @since 4.1.10
     */
    public static int checkBetween(int value, int min, int max) {
        return checkBetween(value, min, max, "The value must be between %s and %s.", min, max);
    }

    /**
     * 检查值是否在指定范围内
     *
     * @param value            值
     * @param min              最小值（包含）
     * @param max              最大值（包含）
     * @param errorMsgTemplate 异常信息模板，类似于"aa{}bb{}cc"
     * @param params           异常信息参数，用于替换"{}"占位符
     * @return 经过检查后的值
     * @since 5.7.15
     */
    public static int checkBetween(int value, int min, int max, String errorMsgTemplate, Object... params) {
        return checkBetween(value, min, max, () -> new IllegalArgumentException(String.format(errorMsgTemplate, params)));
    }


    /**
     * 检查值是否在指定范围内
     *
     * @param <X>           异常类型
     * @param value         值
     * @param min           最小值（包含）
     * @param max           最大值（包含）
     * @param errorSupplier 错误抛出异常附带的消息生产接口
     * @return 经过检查后的值
     * @throws X if value is out of bound
     * @since 5.7.15
     */
    public static <X extends Throwable> int checkBetween(int value, int min, int max, Supplier<? extends X> errorSupplier) throws X {
        if (value < min || value > max) {
            throw errorSupplier.get();
        }

        return value;
    }


    /**
     * 获取堆栈信息
     *
     * @param throwable 异常
     */
    public static String getStackTrace(final Throwable throwable) {
        final StringWriter sw = new StringWriter();
        final PrintWriter pw = new PrintWriter(sw, true);
        throwable.printStackTrace(pw);
        return sw.getBuffer().toString();
    }


    /**
     * 抛出系统异常
     *
     * @param message 异常信息
     */
    public static void throwSys(String message) {
        throw new SystemException(message);
    }

    /**
     * 抛出业务异常
     *
     * @param message 异常信息
     */
    public static void throwBiz(String message) {
        throw new SystemException(message);
    }


    /**
     * 返回业务异常
     *
     * @param message 异常信息
     */
    public static BusinessException getBiz(String message) {
        return new BusinessException(message);
    }
}
